package com.jackrain.nea.omslocal.Dao;

import com.alibaba.dubbo.common.utils.NetUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.util.TypeUtils;
import com.jackrain.nea.config.PropertiesConf;
import com.jackrain.nea.omslocal.service.GetSqunceService;
import com.jackrain.nea.omslocal.service.LocalLogService;
import com.jackrain.nea.omslocal.service.SendMqServies;
import com.jackrain.nea.omslocal.util.JsonKeyCheck;
import com.jackrain.nea.omslocal.util.RegexDateUtil;
import com.jackrain.nea.util.ApplicationContextHandle;
import com.jackrain.nea.util.Tools;
import com.jackrain.nea.util.Validator;
import com.jackrain.nea.web.query.QueryEngine;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.SQLException;
import java.util.*;

/**
 * Description: 保存淘宝订单数据
 * Created with IntelliJ IDEA.
 * User: cs
 * Date: 2017/3/29
 * Time: 18:37
 */
@Slf4j
@Component
public class TaobaoOrderDao {

    @Autowired
    private RegexDateUtil regexDate;
    @Autowired
    private LocalLogService localLogService;
    private FastDateFormat fastformat = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
    @Autowired
    private SendMqServies sendMq;
    @Autowired
    private GetSqunceService getSqunceService;

    /**
     * 保存订单的总方法
     *
     * @param taobaoorderArr
     * @param msgkey
     */
    public void orderStart(JSONArray taobaoorderArr, String msgkey, String topic) throws Exception {
        TaobaoOrderDao taobaoOrderDao = ApplicationContextHandle.getBean(TaobaoOrderDao.class);
        PropertiesConf pconf = (PropertiesConf) ApplicationContextHandle.getBean("propertiesConf");
        // 定义接收消费日志信息的 jsonobject
        JSONObject infoObj = new JSONObject();
        int countFaild = 0;
        // 定义 接收 订单 tid
        List tids = new ArrayList();
        //  需要解析订单结构,分离数据

        for (Object obj : taobaoorderArr) {

            Long tid = 0L;
            JSONObject tempObj = null;
            JSONObject attrObj = null;
            JSONArray ordersArr = null;
            JSONArray promotionArr = new JSONArray();

            try {
                // 循环遍历拿到单条订单数据
                JSONObject firstObj = JSONObject.parseObject(obj.toString(), Feature.OrderedField);
                tempObj = firstObj.getJSONObject("jdp_response").getJSONObject("trade_fullinfo_get_response").getJSONObject("trade");
                //tempObj = firstObj.getJSONObject("trade_fullinfo_get_response").getJSONObject("trade");
                tid = tempObj.getLong("tid");
                log.debug("order start : " + " tid : " + tid);
                String type = "fixed";
                String status = "WAIT_BUYER_PAY";
                if (type.equals(tempObj.getString("type")) && status.equals(tempObj.getString("status"))){
                   // 订单为 正常订单且状态为 WAIT_BUYER_PAY
                    continue;
                }
                if (null != tempObj.getJSONObject("trade_attr")) {
                    // 是天猫菜鸟直送订单
                    attrObj = tempObj.getJSONObject("trade_attr");
                    if (attrObj.containsKey("3plTiming")){
                        // 包含该字段，需要替换该字段
                        String  threePlTiming = attrObj.getString("3plTiming");
                        attrObj.remove("3plTiming");
                        attrObj.put("THREEPLTIMING", threePlTiming);
                    }
                }
                tempObj.remove("service_tags");
                // 明细表数据
                ordersArr = tempObj.getJSONObject("orders").getJSONArray("order");
                // 优惠表数据
                if (tempObj.getJSONObject("promotion_details") != null) {
                    promotionArr = tempObj.getJSONObject("promotion_details").getJSONArray("promotion_detail");
                }

                // 订单表主表数据
                tempObj.remove("orders");
                tempObj.remove("promotion_details");
                tempObj.remove("omni_attr");

                // 根据 tid查询数据库,判断该数据是 新增 或是 修改
                String selectSql = "SELECT id FROM T_OMSTAOBAOORDER WHERE tid = ?";
                int id = Tools.getInt(QueryEngine.getInstance().doQueryOne(selectSql, new Object[]{tid}), -1);

                if (id < 0) {
                    // 新增主表子表
                    taobaoOrderDao.insert(tempObj, ordersArr, promotionArr, topic, attrObj);
                    // 保存数据到本地日志表
                    localLogService.insertLogDeatail(tempObj, tempObj.getLong("tid"), 1, topic, msgkey);
                } else {
                    taobaoOrderDao.update(tempObj, ordersArr, id, topic, attrObj);
                    // 保存数据到本地日志表
                    localLogService.insertLogDeatail(tempObj, tempObj.getLong("tid"), 2, topic, msgkey);
                }

                tids.add(tid);
            } catch (Exception e) {
                // 获取流
                StringWriter sw = new StringWriter();
                PrintWriter pw = new PrintWriter(sw);
                // 逐条将错误信息以消息发送到线上发送到线上
                JSONObject errObj = new JSONObject();
                errObj.put("bus_id", tid);
                errObj.put("tablename", pconf.getProperty("ons.tborder"));
                errObj.put("topic", topic);
                errObj.put("tag", pconf.getProperty("ons.comp"));
                errObj.put("msgkey", msgkey);
                // 线下消费报错的主机 ip
                errObj.put("client_ip", NetUtils.getLocalAddress());
                // 将错误以流写出
                e.printStackTrace(pw);
                errObj.put("errmsg", sw.toString());
                errObj.put("protime", System.currentTimeMillis());
                errObj.put("code", -1);
                sendMq.sendMqinfoObj(errObj, pconf.getProperty("ons.loginfor.suf.topic"), pconf.getProperty("ons.loginfor.suf.tag"));
                log.debug("订单插入失败 : tid :" + tid + "msgkey : " + msgkey + sw.toString());
                // 处理异常  1.将错误信息发送到线上  2. 将错误信息保存到本地数据库
                countFaild++;
                localLogService.insertLog(e.getMessage(), tempObj, tid, topic, msgkey);

            }

        }
        // 调用更新线上日志的服务
        infoObj.put("msgkey", msgkey);
        infoObj.put("client_ip", NetUtils.getLocalAddress());
        infoObj.put("topic", topic);
        infoObj.put("countsuccess", (taobaoorderArr.size() - countFaild));
        infoObj.put("protime", System.currentTimeMillis());
        infoObj.put("tids", tids);
        infoObj.put("code", 0);
        infoObj.put("total", taobaoorderArr.size());
        // 消费完成,将消费的消息信息发送至线上,更新线上日志表
        // 参数 1 消息体  2 消息 topic  3 消息 tag
        String msgId = sendMq.sendMqinfoObj(infoObj, pconf.getProperty("ons.loginfor.suf.topic"), pconf.getProperty("ons.loginfor.suf.tag"));
        if("-1".equals(msgId)){
            for(int i = 0; i < 3; i++){
                if(!"-1".equals(msgId)){
                    break;
                }
                //重试回执
                msgId = sendMq.sendMqinfoObj(infoObj, pconf.getProperty("ons.loginfor.suf.topic"), pconf.getProperty("ons.loginfor.suf.tag"));
            }
        }
        log.debug("taobaoorder消费完成回执 msgId= {}, topic= {}, tag= {}", msgId, pconf.getProperty("ons.loginfor.suf.topic"), pconf.getProperty("ons.loginfor.suf.tag"));
    }

    @Transactional(rollbackFor = Exception.class)
    public void insert(JSONObject tempObj, JSONArray ordersArr, JSONArray promotionArr, String topic, JSONObject attrObj) throws Exception {
        Object outId = null;
        // 新增数据
        // 数据不为空 保存数据
        if (tempObj != null || tempObj.isEmpty()) {
            Map map = null;
            map = saveOrder(tempObj, attrObj);
            outId = map.get("seq");
        } else {
            log.debug("主表数据为空");
        }
        if (ordersArr != null) {
            log.debug("drders 订单商品明细");
            saveOrderProductDetal(ordersArr, "T_OMSTAOBAOPRODUCT", outId);
        } else {
            log.debug("drders 订单商品明细表为空");
        }
        if (promotionArr != null) {
            log.debug("drders 订单优惠表");
            saveOrderPromotionDetal(promotionArr, "T_OMSTAOBAOPROMOTION", outId);
        } else {
            log.debug("drders 订单优惠表为空");
        }

        // 在执行完之后需要更改主表的 istrans 字段为 0
        String sql = "update T_OMSTAOBAOORDER SET istrans = 0 WHERE id = ?";
        QueryEngine.getInstance().executeUpdate(sql, new Object[]{outId});


    }

    @Transactional
    public void update(JSONObject tempObj, JSONArray ordersArr, int id, String topic, JSONObject attrObj) throws Exception {

        if (tempObj != null) {
            // 根据查询到的 id 更新主表数据
            this.updateOrder(tempObj, id, attrObj);
        } else {
            log.error("主表数据为空");
        }
        if (ordersArr != null) {
            // 更新子表 订单商品明细表数据
            this.updateOrderProductDetal(ordersArr, "T_OMSTAOBAOPRODUCT", "oid");

        } else {

            log.error("子表表数据为空");
        }

        // 更新操作之后需要更新 istrans 为0
        String sql = "update T_OMSTAOBAOORDER SET istrans = 0 WHERE id = ?";
        QueryEngine.getInstance().executeUpdate(sql, new Object[]{id});

    }

    /**
     * 保存订单主表
     *
     * @param jsonObj
     * @return
     * @throws SQLException
     */
    public Map saveOrder(JSONObject jsonObj, JSONObject attrObj) throws Exception {

        synchronized (this) {
            JsonKeyCheck checkjson = (JsonKeyCheck) ApplicationContextHandle.getBean(JsonKeyCheck.class);
            jsonObj = checkjson.checkJsonkeycache(jsonObj, "T_OMSTAOBAOORDER", checkjson.getInsertcolsmap());
        }
        Map map = new HashMap();

        String squnceSql = "select get_wsequences('T_OMSTAOBAOORDER') as SEQ from dual";
        int id = TypeUtils.castToInt(QueryEngine.getInstance().doQueryOne(squnceSql));

        jsonObj.put("id", id);

        if (attrObj != null) {
            jsonObj.putAll(attrObj);
        }

        String columnName = "";
        String columnValue = "";
        Set set = jsonObj.keySet();
        Object[] objArr = jsonObj.values().toArray();

        for (Object obj1 : set) {
            columnName = columnName + "," + obj1;
        }
        columnName = columnName.substring(1);

        for (int i = 0; i < objArr.length; i++) {

            if (objArr[i] instanceof String) {
                if (regexDate.regexDate(((String) objArr[i]))) {
                    Date date = fastformat.parse(((String) objArr[i]));
                    objArr[i] = date;
                }
            }
            columnValue = columnValue + ",?";
        }

        columnValue = columnValue.substring(1);

        String sql = "insert into T_OMSTAOBAOORDER (" + columnName + ") values (" + columnValue + ")";
        int code = QueryEngine.getInstance().executeUpdate(sql, objArr);

        map.put("code", code);
        map.put("seq", id);
        return map;
    }

    /**
     * 保存订单商品子表
     *
     * @param dataArr
     * @return
     * @throws SQLException
     */
    public int saveOrderProductDetal(JSONArray dataArr, String tableName, Object outObj) throws Exception {


        for (Object obj : dataArr) {
            JSONObject jsonObj = JSONObject.parseObject(obj.toString(), Feature.OrderedField);

            synchronized (this) {
                JsonKeyCheck checkjson = (JsonKeyCheck) ApplicationContextHandle.getBean(JsonKeyCheck.class);
                jsonObj = checkjson.checkJsonkeycache(jsonObj, "T_OMSTAOBAOPRODUCT", checkjson.getInsertcolsmap());
            }

            // 将固定需要维护的字段加入 jsonObj,  creatTime, modified
            // 获取子表的 sequences
            String squnceSql = "select get_wsequences('" + tableName + "') as SEQ from dual";
            Long id = TypeUtils.castToLong(QueryEngine.getInstance().doQueryOne(squnceSql));

            jsonObj.put("id", id);
            jsonObj.put("OMSTaobaoOrderId", outObj);
            String columnName = "";
            String columnValue = "";
            Set set = jsonObj.keySet();
            Object[] objArr = jsonObj.values().toArray();

            for (Object obj1 : set) {
                columnName = columnName + "," + obj1;
            }
            columnName = columnName.substring(1);

            for (int i = 0; i < objArr.length; i++) {

                if (objArr[i] instanceof String) {
                    if (regexDate.regexDate(((String) objArr[i]))) {
                        Date date2 = fastformat.parse(((String) objArr[i]));
                        objArr[i] = date2;
                    }
                }
                columnValue = columnValue + ",?";
            }
            columnValue = columnValue.substring(1);

            String sql = "insert into " + tableName + " (" + columnName + ") values (" + columnValue + ")";

            int code = QueryEngine.getInstance().executeUpdate(sql, objArr);
        }

        return dataArr.size();
    }

    /**
     * 保存订单优惠子表
     *
     * @param dataArr
     * @return
     * @throws SQLException
     */
    public int saveOrderPromotionDetal(JSONArray dataArr, String tableName, Object outObj) throws Exception {

        for (Object obj : dataArr) {
            JSONObject jsonObj = JSONObject.parseObject(obj.toString(), Feature.OrderedField);

            synchronized (this) {
                JsonKeyCheck checkjson = (JsonKeyCheck) ApplicationContextHandle.getBean(JsonKeyCheck.class);
                jsonObj = checkjson.checkJsonkeycache(jsonObj, "T_OMSTAOBAOPROMOTION", checkjson.getInsertcolsmap());
            }
            // 将固定需要维护的字段加入 jsonObj,  creatTime, modified
            // 获取子表的 sequences
            String squnceSql = "select get_wsequences('" + tableName + "') as SEQ from dual";
            Long id = TypeUtils.castToLong(QueryEngine.getInstance().doQueryOne(squnceSql));

            jsonObj.put("id", id);
            jsonObj.put("OMSTaobaoOrderId", outObj);
            String columnName = "";
            String columnValue = "";
            Set set = jsonObj.keySet();
            Object[] objArr = jsonObj.values().toArray();

            for (Object obj1 : set) {
                columnName = columnName + "," + obj1;
            }
            columnName = columnName.substring(1);

            for (int i = 0; i < objArr.length; i++) {

                if (objArr[i] instanceof String) {
                    if (regexDate.regexDate(((String) objArr[i]))) {
                        Date date2 = fastformat.parse(((String) objArr[i]));
                        objArr[i] = date2;
                    }
                }
                columnValue = columnValue + ",?";
            }
            columnValue = columnValue.substring(1);

            String sql = "insert into " + tableName + " (" + columnName + ") values (" + columnValue + ")";

            int code = QueryEngine.getInstance().executeUpdate(sql, objArr);
        }
        return dataArr.size();
    }

    /**
     * 更新订单主表
     *
     * @param jsonObj
     * @return
     * @throws SQLException
     */
    public void updateOrder(JSONObject jsonObj, int id, JSONObject attrObj) throws Exception {


        JsonKeyCheck checkjson = (JsonKeyCheck) ApplicationContextHandle.getBean(JsonKeyCheck.class);
        jsonObj = checkjson.checkJsonkeycache(jsonObj, "T_OMSTAOBAOORDER", checkjson.getUpdatecolsmap());
        // 加入字段
        if (attrObj != null) {
            jsonObj.putAll(attrObj);
        }
        String params = "";
        Set set = jsonObj.keySet();
        Object[] objArr = jsonObj.values().toArray();
        for (Object obj1 : set) {
            Object tempobject = jsonObj.get(obj1);
            params = params + "" + obj1 + " = ?,";
        }
        for (int i = 0; i < objArr.length; i++) {

            if (Validator.isNull(objArr[i])) {
                objArr[i] = "null";
            }
            if (objArr[i] instanceof String) {
                if (regexDate.regexDate(((String) objArr[i]))) {
                    Date date2 = fastformat.parse(((String) objArr[i]));
                    objArr[i] = date2;
                }
            }
        }

        params = params.substring(0, params.length() - 1);

        String sql = "update T_OMSTAOBAOORDER set " + params + " where id = ?";
        int code = QueryEngine.getInstance().executeUpdate(sql, ArrayUtils.add(objArr, id));

    }

    /**
     * 更新订单子表
     *
     * @param dataArr
     * @return
     * @throws SQLException
     */
    public int updateOrderProductDetal(JSONArray dataArr, String tableName, String outkey) throws Exception {

        for (Object obj : dataArr) {
            JSONObject jsonObj = JSONObject.parseObject(obj.toString(), Feature.OrderedField);

            JsonKeyCheck checkjson = (JsonKeyCheck) ApplicationContextHandle.getBean(JsonKeyCheck.class);
            jsonObj = checkjson.checkJsonkeycache(jsonObj, "T_OMSTAOBAOPRODUCT", checkjson.getUpdatecolsmap());

            // 根据唯一外键查询判断 该数据是否存在,存在就更新数据  不存在暂不操作,
            String selectSql = "select id from " + tableName + " where " + outkey + " = ?";
            Long oid = TypeUtils.castToLong(jsonObj.get(outkey));
            int id = Tools.getInt(QueryEngine.getInstance().doQueryOne(selectSql, new Object[]{oid}), -1);
            if (id < 0) {
                // 数据不存在
                log.debug(outkey + ":" + jsonObj.get(outkey));
                continue;
            }

            // 将固定需要维护的字段加入 jsonObj,
            String params = "";
            Set set = jsonObj.keySet();
            Object[] objArr = jsonObj.values().toArray();
            for (Object obj1 : set) {
                Object tempobject = jsonObj.get(obj1);
                params = params + "" + obj1 + " = ?,";
            }
            params = params.substring(0, params.length() - 1);

            for (int i = 0; i < objArr.length; i++) {

                if (objArr[i] instanceof String) {
                    if (regexDate.regexDate(((String) objArr[i]))) {
                        Date date2 = fastformat.parse(((String) objArr[i]));
                        objArr[i] = date2;
                    }
                }
            }

            String sql = "update " + tableName + " set " + params + " where id = ? ";
            int code = QueryEngine.getInstance().executeUpdate(sql, ArrayUtils.add(objArr, id));

        }
        return dataArr.size();
    }

    /**
     * 更新订单子表
     *
     * @param dataArr
     * @return
     * @throws SQLException
     */
    public int updateOrderPromotionDetal(JSONArray dataArr, String tableName, String outkey) throws Exception {

        for (Object obj : dataArr) {

            JSONObject jsonObj = JSONObject.parseObject(obj.toString(), Feature.OrderedField);
            // 根据唯一外键查询判断 该数据是否存在,存在就更新数据  不存在暂不操作,
            String selectSql = "select id from " + tableName + " where " + outkey + " = ?";
            // Long id = TypeUtils.castToLong(QueryEngine.getInstance().doQueryObject(selectSql, new Object[]{jsonObj.get(outkey)}));
            int id = Tools.getInt(QueryEngine.getInstance().doQueryOne(selectSql, new Object[]{jsonObj.get(outkey)}), -1);

            if (id < 0) {
                // 数据不存在 ,
                log.debug(outkey + ":" + jsonObj.get(outkey));
                continue;
            }
            // 将固定需要维护的字段加入 jsonObj
            String params = "";
            Set set = jsonObj.keySet();
            Object[] objArr = jsonObj.values().toArray();
            for (Object obj1 : set) {

                Object tempobject = jsonObj.get(obj1);
                params = params + "" + obj1 + " = ?,";

            }
            params = params.substring(0, params.length() - 1);

            for (int i = 0; i < objArr.length; i++) {

                if (objArr[i] instanceof String) {
                    if (regexDate.regexDate(((String) objArr[i]))) {
                        Date date2 = fastformat.parse(((String) objArr[i]));
                        objArr[i] = date2;
                    }
                }
            }

            String sql = "update " + tableName + " set " + params + " where id = ? ";
            int code = QueryEngine.getInstance().executeUpdate(sql, ArrayUtils.add(objArr, id));
        }
        return dataArr.size();
    }

}
